﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace DiskGarden
{
	public class SearchEngine
	{
		private NodeType nodeType;
		private bool byName;
		private bool byTags;
		private string word;
		private CategoryNode root;
		private StringComparison stringComparison;

		private bool isSearchingNow = false;
		public bool IsSearchingNow { get { return isSearchingNow; } }
		private Thread thread;

		public event NodeEventHandler NodeFound;
		public event BasicEventHandler SearchCompleted;


		public SearchEngine(CategoryNode root)
		{
			this.root = root;
			nodeType = (NodeType)int.MaxValue;
			byName = true;
			byTags = true;
			stringComparison = StringComparison.CurrentCultureIgnoreCase;
		}

		public void SetPreferences(bool byName, bool byTags, bool ingoreCase)
		{
			this.byName = byName;
			this.byTags = byTags;
			if (ingoreCase)
				this.stringComparison = StringComparison.CurrentCultureIgnoreCase;
			else
				this.stringComparison = StringComparison.CurrentCulture;
		}


		public void StartSearch(string word)
		{
			this.word = word;
			thread = new Thread(Search0);
			thread.Priority = ThreadPriority.Lowest;
			thread.IsBackground = true;
			thread.Start();
		}

		public void StopSearch()
		{
			if (thread != null)
			{
				if (thread.IsAlive)
					thread.Abort();
				thread = null;
			}
		}

		private void Search0()
		{
			try
			{
				Search2(root);
			}
			finally
			{
				isSearchingNow = false;
				if (SearchCompleted != null)
					SearchCompleted();
			}
		}


		private void Search2(object nodeObj)
		{
			Node node1 = (Node)nodeObj;
			if (node1.Type == NodeType.Category || node1.Type == NodeType.Root)
			{
				CategoryNode node = (CategoryNode)node1;
				foreach (Node obj in node.Categories)
					Search2(obj);
				foreach (Node obj in node.Volumes)
				{
					Search2(obj);
				}
			}
			else if (node1.Type == NodeType.Directory || node1.Type == NodeType.Volume)
			{
				CheckNode(node1);
				DirectoryNode node = (DirectoryNode)node1;
				for (int j = 0; j < node.Dirs.Count; j++)
				{
					Search2(node.Dirs[j]);
				}
				for (int j = 0; j < node.Files.Count; j++)
					Search2(node.Files[j]);

			}
			else
				CheckNode(node1);
		}

		//private void Search()
		//{
		//    if (isSearchingNow) return;
		//    try
		//    {
		//        isSearchingNow = true;
		//        List<Node> nodes = new List<Node>(512);
		//        nodes.Add(root);
		//        for (int i = 0; i < nodes.Count; i++)
		//        {
		//            if (nodes[i].Type == NodeType.Category || nodes[i].Type == NodeType.Root)
		//            {
		//                CategoryNode node = (CategoryNode)nodes[i];
		//                //for (int j = 0; j < node.Categories.Count; j++)
		//                //    nodes.Add(node.Categories[j]);
		//                //for (int j = 0; j < node.Volumes.Count; j++)
		//                //    nodes.Add(node.Volumes[j]);
		//                foreach (Node obj in node.Categories)
		//                    nodes.Add(obj);
		//                foreach (Node obj in node.Volumes)
		//                    nodes.Add(obj);
		//            }
		//            else if (nodes[i].Type == NodeType.Directory || nodes[i].Type == NodeType.Volume)
		//            {
		//                CheckNode(nodes[i]);
		//                DirectoryNode node = (DirectoryNode)nodes[i];
		//                for (int j = 0; j < node.Dirs.Count; j++)
		//                    nodes.Add(node.Dirs[j]);
		//                for (int j = 0; j < node.Files.Count; j++)
		//                    nodes.Add(node.Files[j]);
		//                //foreach (Node obj in node.Dirs)
		//                //    nodes.Add(obj);
		//                //foreach (Node obj in node.Files)
		//                //    nodes.Add(obj);
		//            }
		//            else
		//                CheckNode(nodes[i]);
		//        }
		//    }
		//    finally
		//    {
		//        isSearchingNow = false;
		//        if (SearchCompleted != null)
		//            SearchCompleted();
		//    }
		//}

		private void CheckNode(Node node)
		{
			if (IsNodeType(node.Type) && NodeFound != null)
			{
				if (byName && node.name.IndexOf(word, stringComparison) >=0)
				{
					NodeFound(node);
					return;
				}
				if (byTags)
					foreach (string tag in node.Tags)
						if (tag.Equals(word, stringComparison))
						{
							NodeFound(node);
							return;
						}
			}
		}

		private bool IsNodeType(NodeType type)
		{
			return (nodeType & type) != 0;
		}
	}
}
